import cv2
import numpy as np
import math

image = cv2.imread('ocr_data_1.jpg')
image_copy = image.copy()

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

ret, binary_image = cv2.threshold(gray, 72, 255, cv2.THRESH_BINARY)

# cv2.imshow('step 1', cv2.resize(binary_image, None, fx=0.5, fy=0.5))
# cv2.waitKey()
# 进行霍夫圆变换检测圆
circles = cv2.HoughCircles(
    binary_image,
    cv2.HOUGH_GRADIENT, dp=1, minDist=100, param1=50, param2=20, minRadius=250, maxRadius=300
)

white_image = np.ones_like(image) * 255
# 如果检测到圆
if circles is not None:
    circles = np.uint16(np.around(circles))
    for i in circles[0, :]:
        # # 画出圆心
        # cv2.circle(image, (i[0], i[1]), 2, (0, 255, 0), 3)
        # # 画出圆
        # cv2.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)
        cv2.circle(white_image, (i[0], i[1]), i[2] - 5, 0, -1)

mask_image = cv2.bitwise_not(white_image)
result_step_1 = cv2.bitwise_and(image, mask_image)

outer_circle_mask = mask_image

cv2.imshow('step 1', cv2.resize(result_step_1, None, fx=0.5, fy=0.5))
cv2.waitKey()

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

ret, binary_image = cv2.threshold(gray, 72, 255, cv2.THRESH_BINARY)

inverted_image = cv2.bitwise_not(binary_image)
# 进行霍夫圆变换检测圆
circles = cv2.HoughCircles(
    inverted_image,
    cv2.HOUGH_GRADIENT, dp=1, minDist=100, param1=50, param2=20, minRadius=150, maxRadius=250
)

white_image = np.ones_like(image) * 255

# 如果检测到圆
if circles is not None:
    circles = np.uint16(np.around(circles))
    for i in circles[0, :]:
        # 画出圆心
        # cv2.circle(result_step_1, (i[0], i[1]), 2, (0, 255, 0), 3)
        # # 画出圆
        # cv2.circle(result_step_1, (i[0], i[1]), i[2], (0, 0, 255), 2)
        cv2.circle(white_image, (i[0], i[1]), i[2] + 5, 0, -1)

mask_image = white_image

inner_circle_mask = mask_image

result_step_2 = cv2.bitwise_and(result_step_1, mask_image)
cv2.imshow('step 2', cv2.resize(result_step_2, None, fx=0.5, fy=0.5))
cv2.waitKey()

both_circle_mask = cv2.bitwise_and(inner_circle_mask, outer_circle_mask)
inverted_both_circle_mask = cv2.bitwise_not(both_circle_mask)
result_step_3 = cv2.bitwise_or(image, inverted_both_circle_mask)
# cv2.imshow('both_circle_mask', cv2.resize(result_step_3, None, fx=0.5, fy=0.5))
# cv2.waitKey()

gray = cv2.cvtColor(result_step_3, cv2.COLOR_BGR2GRAY)

ret, binary_image = cv2.threshold(gray, 72, 255, cv2.THRESH_BINARY)
cv2.imshow('step 3', cv2.resize(binary_image, None, fx=0.5, fy=0.5))
cv2.waitKey()


# 定义膨胀的核（卷积核）
kernel = np.ones((15, 15), np.uint8)

# 膨胀操作
dilated_image = cv2.dilate(cv2.bitwise_not(binary_image), kernel, iterations=1)

# 显示原始图像、二值化图像和膨胀后的图像
# cv2.imshow('1', cv2.resize(image, None, fx=0.5, fy=0.5))
# cv2.waitKey(0)
# cv2.imshow('1', cv2.resize(binary_image, None, fx=0.5, fy=0.5))
# cv2.waitKey(0)
# cv2.imshow('1', cv2.resize(dilated_image, None, fx=0.5, fy=0.5))
# cv2.waitKey()

inverted_dilated_image = cv2.bitwise_not(binary_image)


contours, _ = cv2.findContours(dilated_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# contours, _ = cv2.findContours(inverted_dilated_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

max_area = 0
max_rect = None
for contour in contours:
    rect = cv2.minAreaRect(contour)
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    area = cv2.contourArea(box)
    if area > max_area:
        max_area = area
        max_rect = box
cv2.drawContours(image, [max_rect], 0, (0, 255, 0), 2)


def distance_to_line(px, py, x1, y1, x2, y2):
    A = y2 - y1
    B = x1 - x2
    C = x2 * y1 - x1 * y2

    distance = abs(A * px + B * py + C) / math.sqrt(A ** 2 + B ** 2)
    return distance < 1
for contour in contours:
    for c in contour:
        px = c[0][0]
        py = c[0][1]
        cv2.circle(image, (px, py), 5, (0, 255, 0), -1)

# 显示结果
cv2.imshow('Intersecting Points on Max Bounding Rectangle', cv2.resize(image, None, fx=0.5, fy=0.5))
cv2.waitKey(0)
interesting_point = []
for i in range(4):
    if i == 2:
        continue
    j = (i + 1) % 4
    x1 = max_rect[i][0]
    y1 = max_rect[i][1]
    x2 = max_rect[j][0]
    y2 = max_rect[j][1]
    ip_flag = True
    min_dis = float('inf')
    fx = 0
    fy = 0
    for contour in contours:
        for c in contour:
            px = c[0][0]
            py = c[0][1]


            # if ip_flag and distance_to_line(px, py, x1, y1, x2, y2):
            #     # print(px, py, x1, y1, x2, y2)
            #     # print(ip_flag)
            #     cv2.circle(image, (px, py), 20, (0, 255, 0), -1)
            #     interesting_point.append((px, py))
            #     ip_flag = False
            if i == 0:
                length = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
                point_to_first_point_dis = math.sqrt((x1 - px) ** 2 + (y1 - py) ** 2)
                if distance_to_line(px, py, x1, y1, x2, y2) and point_to_first_point_dis < min_dis:
                    kx = px
                    ky = py
                    fx = px
                    fy = py
                    min_dis = point_to_first_point_dis
            else:
                point_to_f_point_dis = math.sqrt((fx - px) ** 2 + (fy - py) ** 2)
                if distance_to_line(px, py, x1, y1, x2, y2) and point_to_f_point_dis < min_dis:
                    kx = px
                    ky = py
                    min_dis = point_to_f_point_dis
    cv2.circle(image, (kx, ky), 20, (0, 255, 0), -1)
    interesting_point.append((kx, ky))
print(interesting_point)
# 显示结果
cv2.imshow('Intersecting Points on Max Bounding Rectangle', cv2.resize(image, None, fx=0.5, fy=0.5))
cv2.waitKey(0)


def find_circle_center_radius(x1, y1, x2, y2, x3, y3):
    # 构建方程组
    A = np.array([[2 * (x2 - x1), 2 * (y2 - y1)],
                  [2 * (x3 - x1), 2 * (y3 - y1)]])
    B = np.array([x2 ** 2 + y2 ** 2 - x1 ** 2 - y1 ** 2,
                  x3 ** 2 + y3 ** 2 - x1 ** 2 - y1 ** 2])

    # 求解方程组
    center = np.linalg.solve(A, B)

    # 计算半径
    radius = np.sqrt((x1 - center[0]) ** 2 + (y1 - center[1]) ** 2)

    return center, radius


center, radius = find_circle_center_radius(interesting_point[0][0],
                                           interesting_point[0][1],
                                           interesting_point[1][0],
                                           interesting_point[1][1],
                                           interesting_point[2][0],
                                           interesting_point[2][1])
print(center, radius)

# 画出圆心
cv2.circle(image, (int(center[0]), int(center[1])), 10, (0, 255, 0), 3)
# 画出圆
cv2.circle(image, (int(center[0]), int(center[1])), int(radius), (0, 0, 255), 2)

cv2.imshow('step result', cv2.resize(image, None, fx=0.5, fy=0.5))
cv2.waitKey(0)

size = int(2 * radius)
x1 = int(center[0] - radius)
y1 = int(center[1] - radius)
x2 = x1 + size
y2 = y1 + size
image_copy = np.array(image_copy)
print(y1, y2, x1, x2)
print(image_copy.shape)
cropped_image = image_copy[y1:y2, x1:x2, :]
cv2.imshow('cropped image', cv2.resize(cropped_image, None, fx=0.5, fy=0.5))
cv2.waitKey(0)

PI = math.pi
line_height_param = 1.8
HEIGHT = size
WIDTH = size
def create_line_image(img):
    CIRCLE_RADIUS = int(HEIGHT / 2)
    CIRCLE_CENTER = [HEIGHT / 2, WIDTH / 2]
    LINE_HEIGHT = int(CIRCLE_RADIUS / line_height_param)
    LINE_WIDTH = int(2 * CIRCLE_RADIUS * PI)
    line_image = np.zeros((LINE_HEIGHT, LINE_WIDTH, 3), dtype=np.uint8)
    for row in range(line_image.shape[0]):
        for col in range(line_image.shape[1]):
            theta = PI * 2 / LINE_WIDTH * (col + 1) + 5
            rho = CIRCLE_RADIUS - row

            x = int(CIRCLE_CENTER[0] + rho * math.cos(theta) + 0.0)
            y = int(CIRCLE_CENTER[1] - rho * math.sin(theta) + 0.0)
            # print(row, col, y, x)
            # print(line_image.shape, img.shape)
            line_image[row, col, :] = img[y, x, :]
    line_image = cv2.rotate(line_image, cv2.ROTATE_180)
    line_image = cv2.flip(line_image, 0)

    cv2.imshow('result', cv2.resize(line_image, None, fx=0.5, fy=0.5))
    cv2.waitKey(0)
    return line_image
line_image = create_line_image(cropped_image)

cv2.destroyAllWindows()
